<?php

namespace App\Http\Controllers\Api;

use App\Exceptions\BusinessException;
use App\Models\ExpressTemplateModel;
use App\Utils\ControllerModelTrait;
use App\Utils\ResponseEnum;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;

class ExpressController extends ApiController
{
    const CACHE_KEY = 'express-';

    private string $kuAiDi100Host= 'https://poll.kuaidi100.com';
    private string $kuAiDi100Key = 'bKdGQzLS6860';
    private string $kuAiDi100Customer = 'E4CD74DF83E37ADC825DDC1FCD750BFF';

    use ControllerModelTrait;

    /**
     * 获取快递模板列表
     * @param Request $request
     * @return JsonResponse
     */
    public function getList(Request  $request): JsonResponse
    {
        $Model = ExpressTemplateModel::where('id', '>', 0);
        if ($request->input('company'))
            $Model = $Model->where('company', $request->input('company'));
        $paginate = $this->getPagedData($Model, $request);
        return $this->successPaginate($paginate);
    }

    /**
     * 保存快递模板
     * @param Request $request
     * @return JsonResponse
     * @throws BusinessException
     */
    public function doSave(Request $request): JsonResponse
    {
        $company = $this->verifyString('company');
        $data = $request->only(['title', 'company', 'code', 'info']);
        $this->saveData(new ExpressTemplateModel, $data);
        self::setCompanyExpressCache($company);
        return $this->success();
    }

    /**
     * 删除快递
     * @return JsonResponse
     * @throws BusinessException
     */
    public function doDelete(): JsonResponse
    {
        $ids = $this->verifyString('ids');
        $this->deleteData(new ExpressTemplateModel, $ids);
        return $this->success();
    }

    /**
     * @throws BusinessException
     * @throws GuzzleException
     */
    public function doQuery(): JsonResponse
    {
        $expressNo = $this->verifyString('express_no');
        $company = $this->verifyString('company');
        $post = $this->getExpressQueryParam($company, $expressNo);
        $response = GuzzlePost($this->kuAiDi100Host, '/poll/query.do', $post);
        $data = json_decode($response, true);
        if ($data && $data['message'] == 'ok')
            return $this->success($data['data']);
        return $this->success([]);
    }

    /**
     * 获取快递价目表
     * @param Request $request
     * @return JsonResponse
     * @throws BusinessException
     */
    public function getExpressFee(Request $request): JsonResponse
    {
        $code = $this->verifyString('code');
        $weight = $this->verifyInteger('weight');
        $companySuffixList = ['菜鸟', '拼多多', '抖音'];
        $expressCompanyList = ['极兔', '中通', '申通', '顺丰'];
        $data = [];
        foreach ($expressCompanyList as $expressCompany) {
            $express = $this->getCodeCompanyPriceTemplate($expressCompany, $code);
            if ($express) {
                $fee =  $this->getPriceFromTemplate($weight, $express);
                foreach ($companySuffixList as $suffix) {
                    $data[] = ['company' => $expressCompany .'（'. $suffix .'）', 'fee' => $fee];
                }
            }
        }
        return $this->success($data);
    }

    /**
     * 根据模板匹配计算公式
     * @param $weight
     * @param $express
     * @return float|int
     */
    private function getPriceFromTemplate($weight, $express): float|int
    {
        if ($weight === 1000 || $weight === 2000)
            $weight += 1000;
        $priceList = json_decode($express->info, true);
        $weightList = array_column($priceList, 'limit');
        sort($weightList);
        $weightLimitValue = 0;
        foreach ($weightList as $limit) {
            if ($limit * 1000 >= $weight) {
                $weightLimitValue = $limit;
                break;
            }
        }
        return $this->evaluateExpressPrice($weight, $weightLimitValue, $priceList);
    }

    /**
     * 计算快递费用
     * @param $weight
     * @param $weightLimitValue
     * @param $priceList
     * @return float|int
     */
    private function evaluateExpressPrice($weight, $weightLimitValue, $priceList): float|int
    {
        $price = 0;
        foreach ($priceList as $priceItem) {
            if ($priceItem['limit'] == $weightLimitValue)
                $price = $priceItem['inc_price'] ? (ceil($weight / 1000) - 1) * $priceItem['inc_price'] + $priceItem['price'] : $priceItem['price'];
        }
        return $price;
    }

    /**
     * 获取快递公司对应地区价格模板
     * @param $company
     * @param $code
     * @return mixed
     */
    private function getCodeCompanyPriceTemplate($company, $code): mixed
    {
        $companyExpressCollection = self::getCompanyExpressCache($company);
        $collection = $companyExpressCollection->filter(function ($item) use ($code) {
            return str_contains($item->code, $code);
        });
        return $collection->first();
    }

    /**
     * 获取快递100快递查询参数
     * @param $company
     * @param $expressNo
     * @return array
     */
    private function getExpressQueryParam($company, $expressNo): array
    {
        $params = json_encode([
            'com' => $this->getKuAiDi100ExpressCompanyCode($company),
            'num' => $expressNo,
        ]);
        $sign = strtoupper(md5($params . $this->kuAiDi100Key . $this->kuAiDi100Customer));
        return  ['customer' => $this->kuAiDi100Customer, 'param' => $params, 'sign' => $sign];
    }

    /**
     * 获取快递100快递公司代码
     * @param $company
     * @return string
     */
    private function getKuAiDi100ExpressCompanyCode($company): string
    {
        return match ($company) {
            'yuantong'          => str_contains($company, '圆通'),
            'yunda'             => str_contains($company, '韵达'),
            'shentong'          => str_contains($company, '申通'),
            'jtexpress'         => str_contains($company, '极兔'),
            'zhongtong'         => str_contains($company, '中通'),
            'youzhengguonei'    => str_contains($company, '邮政'),
            'shunfeng'          => str_contains($company, '顺丰'),
            default             => 'jtexpress',
        };
    }

    /**
     * 获取对应快递公司的缓存
     * @param $company
     * @return mixed
     */
    public static function getCompanyExpressCache($company): mixed
    {
        if (!Cache::has(self::CACHE_KEY . $company))
            self::setCompanyExpressCache($company);
        return Cache::get(self::CACHE_KEY . $company);
    }

    /**
     * 创建对应快递公司的缓存
     * @param $company
     * @return void
     */
    public static function setCompanyExpressCache($company): void
    {
        $expressCollection = ExpressTemplateModel::where('company', $company)->get();
        Cache::put(self::CACHE_KEY . $company, $expressCollection);
    }
}
